'''
s7界面调试主程序
'''
import enum
import sys
import os
import threading
import time
import traceback

from PyQt5 import QtWidgets
from PyQt5.QtCore import pyqtSignal, Qt, QTimer, QDateTime
from PyQt5.QtGui import QFont, QTextCursor, QTextOption, QIcon
from PyQt5.QtWidgets import QApplication, QHeaderView, QMessageBox

# from ui.shwj_ui import Ui_MainWindow  # 界面控件， QtDesigner生成
from ui.shwj_ui_v2 import Ui_MainWindow  # 界面控件， QtDesigner生成

from engine import Engine, pnplcAdsStr2pnplcAds # engine
from log import logger

from ui.set_table_widget import NonMainTableWidget # 子界面 配置pn_plc
from ui.sub_debug_class import SubDebugWidget # 子界面 手动触发
from ui.login_class import LoginWidget # 登录子界面


from util.util import ui_util as UI_UTIL
from datetime import datetime as py_datetime

def show_kv_dict2show_ko_dict(show_kv_dict, show_ko_dict): # 递归方式
    '''
    key_value 同步到 key_object
    :param show_kv_dict:
    :param show_ko_dict:
    :return:
    '''
    for k, pend_obj in show_ko_dict.items():
        if not isinstance(pend_obj, dict): # 递归出口
            value, is_update = show_kv_dict[k]
            if isinstance(pend_obj, (QtWidgets.QLineEdit, QtWidgets.QLabel)): # label和 lineEdit控件逻辑
                # 转换后端值
                if isinstance(value, enum.Enum):
                    value = value.value
                elif isinstance(value, int):
                    value = str(value)

                # value 2 obj
                pre_value = pend_obj.text()
                # ls = pre_value.split('/n')
                # last_value = ls[-1] if len(ls)==0 else pre_value
                if is_update:
                    # value = pre_value + '\n' + value # 滚动
                    if value in ('未启动', 'NG'):
                        pend_obj.setStyleSheet("background-color: red;font-size: 15pt;")
                    elif value in ('未使用'):
                        pend_obj.setStyleSheet("background-color: gray;font-size: 15pt;")
                    elif value in ('PASS', '已启动','比对中','打印中','上传中','等待打印','等待扫码结果','等待上传'):
                        pend_obj.setStyleSheet("background-color: green;font-size: 15pt;")
                    elif value in ('\N{NO ENTRY}未连接', '\N{NO ENTRY}仿真未连接'):
                        pend_obj.setStyleSheet("background-color: red;")
                    # time_str = py_datetime.now().strftime('%Y/%m/%d %H:%M:%S')
                    # pend.setText( time_str + value)
                    pend_obj.setText(value)
                    show_kv_dict[k][-1] = 0 # is_update置为False todo 同步
                    print(f'{pre_value} 设置为 {value}')

            elif isinstance(pend_obj, QtWidgets.QTableWidget): # 表格控件 mess产品信息
                # 无变化不更新
                value, is_update = show_kv_dict[k]
                if is_update:
                    UI_UTIL.tableValue2tableObj(det_record_kv_list=value, tableWidget=pend_obj) # v2o
                    show_kv_dict[k][-1] = 0  # is_update置为False todo 同步
                pass
        else:
            show_kv_dict2show_ko_dict(show_kv_dict[k], show_ko_dict[k])

# show_kv_dict2show_ko_dict(self.engine.show_dict['running_thread_info'], self.show_ko_dict['running_thread_info'])

class MyQMainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    statusChangeSignal = pyqtSignal(list)
    productInforSignal = pyqtSignal(list)

    def __init__(self, parent=None):
        super(MyQMainWindow, self).__init__(parent)
        # 注册自定义处理器
        # logger.remove()  # 先移除默认处理器
        logger.add(self.append_to_textbrowser)

        self.setupUi(self) # 建立控件和布局
        self.extend_unicode_icon()
        self.statusChangeSignal.connect(self.statusChange_slot)
        self.productInforSignal.connect(self.productInfor_slot)

        self.comboBox.currentIndexChanged.connect(self.sqlwebChanged_slot)# sql web

        # 每个1s执行self.update_time_slot槽函数
        self.timer = QTimer(self)  # 创建定时器
        self.timer.setInterval(1000)  # 设置间隔为 1 秒
        self.timer.timeout.connect(self.update_time_slot)  # 连接 timeout 信号到 update_time 槽函数
        self.update_time_slot()  # 初始时更新一次时间
        self.timer.start()  # 开始定时器


        self.engine = Engine(isUI=True, ui_handle=self)

        # self.status = 'Sleeping' # Sleeping, Running
        # 构造子界面
        self.ui_Form = NonMainTableWidget(data=self.engine.pn_plc_dict)
        self.subDebugWidget = SubDebugWidget(main_ui_handle=self)

        self.loginWidget = LoginWidget(subDebugWidget=self.subDebugWidget)


        # 额外样式
        icon_path = "ui/imgs/LOGO.png"  # 替换成您的 logo 图片文件的实际路径
        window_icon = QIcon(icon_path)
        self.setWindowIcon(window_icon)# 设置主窗口的 logo
        self.setStyleSheet("""
                /*color:rgb(255, 255, 255);background-color: #38406E;*/
                QPushButton {
                    min-width: 80px;
                    padding: 5px;
                    border-radius: 3px;
                    color: white;
                    background-color: dodgerblue;
                }
                #comboBox {
                    min-width: 40px;
                    padding: 5px;
                    border-radius: 3px;
                    color: white;
                    background-color: dodgerblue;
                }
                QPushButton:hover {
                    background-color: darkblue;
                }
                #checkBox { /*QCheckBox*/
                    min-width: 80px;
                    padding: 5px;
                    border-radius: 3px;
                    color: white;
                    background-color: dodgerblue;
                }
                QLabel {
                    border-radius: 5px;
                }
                
                /* 定义 QGroupBox 样式 */
                QGroupBox {
                    /*font-size: 14px;*/
                    font-weight: bold;
                    border: 1px solid #ccc;
                    border-radius: 8px; /* 使用像素值代替分数 */
                    padding: 0.5em;
                    margin-top: 0.5em;
                    background-color: #f5f5f5;
                }

                /* 设置标题样式 */
                QGroupBox::title {
                    subcontrol-origin: margin;
                    /*subcontrol-position: top center;*/
                    padding: 0 1em;
                    color: #333;
                    background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
                                                    stop: 0 #f5f5f5, stop: 1 #e5e5e5);
                    border-bottom: 1px solid #ccc;
                    border-top-left-radius: 8px;
                    border-top-right-radius: 8px;
                }
                
                /* 为内部控件添加内边距 ，所有QGroupBox的直接子控件
                QGroupBox > * {
                    margin: 0.5em;
                }*/
                
                /*QMainWindow {
                    background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1,
                                                    stop: 0 #f5f5f5, stop: 1 #e5e5e5);
                }*/
                
                /* 输入框样式 */
                QLineEdit {
                    border: 1px solid #ccc; /* 边框颜色 */
                    border-radius: 4px; /* 边框圆角 */
                    background-color: #fff; /* 背景颜色 */
                }
                /* 输入框焦点样式 */
                QLineEdit:focus {
                    border-color: #80bfff; /* 焦点边框颜色 */
                }

            """)
        # self.function_gbox.setStyleSheet("""x""")
        # self.log_gbox.setStyleSheet("""x""")
        # 创建字体对象并设置字体样式
        font = QFont("Arial", 10, QFont.Bold)  # 这里设置了字体为 Arial，大小为 12 点，粗体
        # 将字体应用到 QTextBrowser
        self.textBrowser.setFont(font)
        # self.textBrowser.setWordWrapMode(QTextOption.WrapAtWordBoundaryOrAnywhere)
        # 设置自动换行模式
        self.textBrowser.setWordWrapMode(QTextOption.WrapAtWordBoundaryOrAnywhere)

        self.tableWidget.horizontalHeader().setSectionResizeMode(
            QHeaderView.Interactive | QHeaderView.Stretch)  # 列宽自适应表格控件大小
        self.tableWidget_2.horizontalHeader().setSectionResizeMode(
            QHeaderView.Interactive | QHeaderView.Stretch)  # 列宽自适应表格控件大小

        # 得和self.engine.show_dict 得key值一致
        self.show_ko_dict = {
            'running_thread_info': { # 运行线程信息
                '点位7手机': {
                    'mess_pn': self.mESSPNLineEdit,
                    'plc_sn': self.LineEdit,
                    'status': self.label_3,  # 等待扫码结果, 比对中， PASS， NG
                },
                '点位2电池': {  # 电池
                    'mess_pn': self.sNLineEdit_4,
                    'plc_pn': self.sNLineEdit_5,
                    'status': self.label_9,  # 等待扫码结果, 比对中， PASS， NG
                },
                '点位3数据线': {
                    'mess_pn': self.sNLineEdit_6,
                    'plc_pn': self.sNLineEdit_7,
                    'status': self.label_10,  # 等待扫码结果, 比对中， PASS， NG
                },
                '点位5说明书': {
                    'mess_pn': self.sNLineEdit_8,
                    'plc_pn': self.sNLineEdit_9,
                    'status': self.label_11,  # 等待扫码结果, 比对中， PASS， NG
                },
                '点位5许可证': {
                    'mess_pn': self.sNLineEdit_10,
                    'plc_pn': self.sNLineEdit_11,
                    'status': self.label_12,  # 等待扫码结果, 比对中， PASS， NG
                },
                '点位6腕带': {
                    'mess_pn': self.sNLineEdit_12,
                    'plc_pn': self.sNLineEdit_13,
                    'status': self.label_13,  # 等待扫码结果, 比对中， PASS， NG
                },
                'label_print': {  # 标贴打印
                    'sn': self.sNLineEdit,  # 打印的sn
                    'pof_path': self.p1LineEdit,  #
                    'status': self.label_7,  # 等待打印, 打印中， 打印完成
                },
                'record_upload': {  # 上传
                    'pn': self.sNLineEdit_2,  # 上传的pn
                    'sn': self.sNLineEdit_3,  # 上传的sn
                    'status': self.label_8,  # 等待上传, 上传中， 上传完成
                },


            },

            'product_info': self.tableWidget, # 产品信息

            'uploaded_record': self.tableWidget_2,  # 已上传记录

            # 'sys_status': '',
            'printer_status': self.label_17, # '已连接' '连接异常'
            'plc_status': self.label_15,
            'mess_status': self.label_19,
            # 'sys_time': self.label_6,
        }
        self.lock_statusChange = threading.Lock()
        self.t1 = time.time()
    def append_to_textbrowser(self, record):
        """自定义处理器，将日志信息追加到QTextBrowser"""
        # # print(record)
        lev = record.record['level'].name
        if lev in ('WARNING', 'ERROR'):
            self.textBrowser.append(record)
        # # 确保文本浏览器滚动到底部
        # self.textBrowser.verticalScrollBar().setValue(self.textBrowser.verticalScrollBar().maximum())
        # 确保最后一行始终可见
        self.textBrowser.ensureCursorVisible()


        # cursor = self.textBrowser.textCursor()
        # cursor.movePosition(QTextCursor.End)
        # cursor.insertHtml(f"<p>{record}</p>")
        # self.textBrowser.ensureCursorVisible()  # 确保光标可见，即滚动至底部
        # self.textBrowser.repaint()  # 强制刷新
        # QApplication.processEvents()  # 处理事件队列，确保界面更新

    def closeEvent(self, event):
        try:
            self.engine.close()
            print('closeEvent Done ')
        except:
            logger.error(traceback.format_exc())
        return 0

    def extend_unicode_icon(self): # 设置图标
        '''
        文本左侧加图标
        :return:
        '''
        self.checkBox.setText('\U0001F6F0'+ self.checkBox.text()) # 模拟
        self.pushButton_2.setText('\U0001F527' + self.pushButton_2.text()) # 调试
        self.pushButton.setText('\U0001F4C2' + self.pushButton.text()) # 打开目录
        self.pushButton_4.setText('\U00002699' + self.pushButton_4.text()) # 设置
        # self.pushButton_3.setText('\U0001F4F1' + self.pushButton_3.text())  # 换型

        self.label_5.setText('\U0001F4C5' + self.label_5.text())  # 时间
        # self.label.setText('\U0001F4C5' + self.label.text())  # 系统状态
        # self.label_14.setText('\U0001F4C5' + self.label_14.text())  # plc
        # self.label_16.setText('\U0001F4C5' + self.label_16.text())  # 打印机
        # self.label_18.setText('\U0001F4C5' + self.label_18.text())  # mes

    def apply_slot(self):

        try:
            # tex = self.pushButton_3.text()
            # if tex == "Apply":
            self.engine.set_is_stop()
            current_text = self.comboBox_3.currentText()
            print(current_text)
            # self.engine.main(isUi=True)
            self.engine.sku = current_text

            # self.engine.plc_main_handle.set_sku(self.engine.sku)  # set 1
            # self.engine.plc_main_handle.set_is_change_product_chufa() # set 1

            self.engine.set_is_init() # check status from stop to init
            # self.engine # start
            # self.pushButton_3.setText("Applied")
            # self.textBrowser
            # self.textBrowser.append("Started.")
            # self.textBrowser.append("Started.")
        except:
            logger.error(traceback.format_exc())

    def statusChange_slot(self): # value 2 object
        '''
        value 2 object
        后端变量engine.show_dict 同步到界面
        :return:
        '''
        try:
            # time.sleep(0.5)
            # self.lock_statusChange.acquire()
            self.label_2.setText(self.engine.STATUS) # 同步系统状态

            # self.show_ko_dict['running_thread_info']['点位7手机']['status'].setText(
            #     self.engine.show_dict['running_thread_info']['点位7手机']['status'])
            #
            # self.show_ko_dict['running_thread_info']['label_print']['status'].setText(
            #     self.engine.show_dict['running_thread_info']['label_print']['status'].value)
            # self.show_ko_dict['running_thread_info']['label_print']['sn'].setText(
            #     self.engine.show_dict['running_thread_info']['label_print']['sn'])
            # self.show_ko_dict['running_thread_info']['label_print']['pof_path'].setText(
            #     self.engine.show_dict['running_thread_info']['label_print']['pof_path'])

            # # 设置运行信息 ['running_thread_info']['label_print']['*']
            # for device_name, v_dict in self.show_ko_dict['running_thread_info'].items():
            #     tex = v_dict['status'].getText()
            #     if tex == self.engine.show_dict['running_thread_info']['label_print']['status']:
            #         pass

            # if self.isDelay(0.5): # 至少相隔500ms
            #     show_kv_dict2show_ko_dict(self.engine.show_dict, self.show_ko_dict)
            show_kv_dict2show_ko_dict(self.engine.show_dict, self.show_ko_dict)
            # self.lock_statusChange.release()
        except:
            print(traceback.format_exc())

    def isDelay(self, delay_second=0.5):
        t2 = time.time()
        if t2 - self.t1 > delay_second:
            self.t1 = t2
            return True
        return False

    def open_log_dir_slot(self):
        # os.startfile(r'C:\zxc\data\shwj')
        os.startfile(r'.\doc\log')


    def productInfor_slot(self): # v1
        try:
             # pn_plc_dict = pnplcAdsStr2pnplcAds(self.engine.pn_plc_dict)
            # show_str = ''
            # for pn in pns:
            #     plc_ads = pn_plc_dict[pn]
            #     # pn_ads = eval(pn_ads) if type(pn_ads)==str else pn_ads
            #     show_str += plc_ads['device_name'] + ' ' + pn +'\n'
            # self.label_3.setText(show_str)
            pass
        except:
            logger.error(traceback.format_exc())

    def is_sim_scan_ok_slot(self):
        try:
            # # tex = self.pushButton_2.text()
            # if self.engine.isSimScanOk == False:
            #     self.engine.isSimScanOk = True
            # else:
            #     self.engine.isSimScanOk = False
            # self.label_4.setText(str(self.engine.isSimScanOk))

            if self.checkBox.isChecked():
                self.engine.isSimScanOk = True
            else:
                self.engine.isSimScanOk = False
            print(f'self.engine.isSimScanOk {self.engine.isSimScanOk}')
        except:
            logger.error(traceback.format_exc())

    def set_slot(self): # button
        self.ui_Form.setWindowModality(Qt.ApplicationModal)  # 设置对话框为模态窗口，防止用户与主窗口交互
        self.ui_Form.show()

    def munal_trigger_btn_slot(self): # o2v
        # 登录
        self.loginWidget.show()

        # msg_box = QMessageBox()
        # msg_box.setWindowTitle('登录')
        # msg_box.setText('已有上传记录，不能手动打印')
        # msg_box.setDefaultButton(QMessageBox.Ok)
        # response = msg_box.exec()
        # if response == QMessageBox.Ok:
        #     print('点击OK')
        #     pass
        #
        # # 打开调试界面
        # self.subDebugWidget.show()


    def update_time_slot(self):
        '''
        更新label的时间
        :return:
        '''
        current_time = QDateTime.currentDateTime().toString('yyyy-MM-dd HH:mm:ss')
        self.label_6.setText(current_time)

    def sqlwebChanged_slot(self,index):
        '''
        check sql web method
        :return:
        '''

        method = self.comboBox.itemText(index)
        logger.error(f'INFO: method set as: {method}')
        self.engine.mess_handle.method = method


if __name__ == '__main__':
    try:
        app = QtWidgets.QApplication(sys.argv)
        app.setWindowIcon(QIcon("ui/imgs/LOGO.png"))
        mainWnd = MyQMainWindow()
        # ui = Ui_MainWindow()
        # ui.setupUi(mainWnd)
        mainWnd.show()
        mainWnd.engine.start() #
        sys.exit(app.exec())
    except:
        print(traceback.format_exc())
        logger.error(traceback.format_exc())